#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>

const std::string HttpSep = "\r\n";
// 记录网页路径
const std::string wwwroot = "./wwwroot";
const std::string homepage = "index.html";

class HttpRequest
{
public:
    HttpRequest() : _req_blank(HttpSep), _path(wwwroot) // 将路径初始化为web根目录，后面每次获取资源都从根目录开始找
    {
    }
    // 获取一行报文信息
    bool GetLine(std::string &request, std::string *line)
    {
        auto pos = request.find(HttpSep); // 通过\r\n分隔
        if (pos == std::string::npos)
            return false;
        *line = request.substr(0, pos);
        request.erase(0, pos + HttpSep.size()); // 获取完一个字段将其删除
        return true;
    }
    void Deserialize(std::string &request)
    {
        std::string line;
        bool ret = GetLine(request, &line); // 先获取请求行
        if (!ret)
            return;
        _req_line = line;
        while (true)
        {
            bool ok = GetLine(request, &line);
            if (ok && line.empty())
            {
                _req_content = request; // 遇到了空行那么剩下的请求就只剩下正文
                break;
            }
            else if (ok && !line.empty())
            {
                _req_header.push_back(line); // 获取请求报头
            }
            else
                break;
        }
    }
    // 解析请求行
    void ParseReqLine()
    {
        std::stringstream ss(_req_line);
        // stringstream 可以根据空格进行分隔字符串，然后我们将其重定向到这些字段中
        ss >> _method >> _url >> _http_version;

        // 如果url是/，我们就给他后面拼接我们首页所在路径
        if (_url == "/")
        {
            _path += _url;
            _path += homepage; // ./wwwroot/index.html
        }
        else
        {
            _path += _url; // 如果是指定的路径我们直接拼接即可
        }
    }
    void ParseSuffix()
    {
        // _path中保存的是要访问的资源路径
        auto pos = _path.rfind(".");
        if (pos == std::string::npos)
            _suffix = ".html";
        else
            _suffix = _path.substr(pos); // 截取文件后缀
    }
    void Parse()
    {
        // 1. 分析请求行
        ParseReqLine();
        // 2. 获取文件后缀
        ParseSuffix();
    }
    // 读取网页文件
    std::string GetFileContentHelper(const std::string &path)
    {
        // 读取Text文本信息
        // std::ifstream in(path, std::ios::binary); // 以二进制形式读取
        // if(!in.is_open()) return "";
        // std::string content;
        // std::string line;
        // while(std::getline(in, line))  // 如果读取图片、音频、视频就会存在BUG
        // {
        //     content += line;
        // }
        // in.close();
        // return content;

        // 优化过后的代码，可以保证读取图片等非文本文件
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return "";
        in.seekg(0, in.end);       // 将文件指针放在最后
        int filesize = in.tellg(); // 返回文件指针的位置，也就是文件总大小
        in.seekg(0, in.beg);       // 将文件指针调回开始
        // 开始读取
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize); // 读取文件大小的内容
        in.close();
        return content;
    }
    std::string GetFileContent()
    {
        return GetFileContentHelper(_path);
    }

    std::string Get_404File()
    {
        return GetFileContentHelper("./wwwroot/404.html");
    }
    // for test
    void DebugHttp()
    {
        std::cout << "_req_line: " << _req_line << std::endl;
        for (auto &line : _req_header)
        {
            std::cout << "---> " << line << std::endl;
        }
        std::cout << "_req_blank: " << _req_blank << std::endl;
        std::cout << "_req_content: " << _req_content << std::endl;
        std::cout << "Method: " << _method << std::endl;
        std::cout << "url: " << _url << std::endl;
        std::cout << "http_version: " << _http_version << std::endl;
    }
    std::string Url()
    {
        return _url;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    ~HttpRequest()
    {
    }

private:
    // 请求报文
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _req_blank;               // 空行
    std::string _req_content;             // 正文部分

    // 请求行三个字段
    std::string _method;       // 请求方法
    std::string _url;          // url资源路径
    std::string _path;         // 访问的url资源路径
    std::string _http_version; // http协议版本
    std::string _suffix;       // 文件的后缀
};

const std::string BlankSep = " ";
const std::string LineSep = "\r\n";

class HttpResponse
{
public:
    HttpResponse() : _http_version("HTTP/1.0"), _status_code(200), _status_code_desc("OK"), _blank(BlankSep)
    {
    }

    // 按照HTTP响应报文序列化
    std::string Serialize()
    {
        std::string response_str = _status_line;
        for(auto &header : _resp_header)
        {
            response_str += header;
        }
        response_str += LineSep;
        response_str += _content;
        return response_str;
    }
    // 按照HTTP响应报文格式拼接状态行
    void MakeStatusLine()
    {
        _status_line = _http_version + BlankSep + std::to_string(_status_code) + BlankSep + _status_code_desc + LineSep;
    }
    // 添加报头
    void AddHeader(const std::string &header)
    {
        _resp_header.push_back(header);
    }
    // 添加正文
    void AddContent(const std::string &content)
    {
        _content = content;
    }
    // 设置状态码
    void SetCode(int code)
    {
        _status_code = code;
    }
    // 设置状态码描述
    void SetDesc(const std::string &desc)
    {
        _status_code_desc = desc;
    }
    ~HttpResponse()
    {
    }

private:
    // 请求报文字段
    std::string _status_line;               // 状态行
    std::vector<std::string> _resp_header; // 请求报头
    std::string _blank;                     // 空行
    std::string _content;                   // 正文

    // 状态行字段
    std::string _http_version;         // HTTP协议版本
    int _status_code;                  // 状态码
    std::string _status_code_desc;     // 状态码描述
};